package fxmedia.ui;

// Import Java JDK Classes
import java.util.Random;

import javafx.application.Platform;
// Import JavaFX Classes
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.EventHandler;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;

// Import Application classes
import fxmedia.Constants;
import fxmedia.FxMedia;
import fxmedia.MediaFile;

/**
 * @author dca
 */
public class LibraryList extends ListView<MediaFile> {
	/**
	 * Constructs the library list.<br/>
	 * @param app The media player application.<br/>
	 */
	public LibraryList(final FxMedia app) {
		super(FXCollections.observableArrayList(app.getPlayer().getLibrary()));
		this.setLibraryListWidth(app);
		this.initSelectionListener(app);
		this.initDoubleClickListener(app);
	} // END constructor

	/**
	 * Sets the library list width is based on longest song size.<br/>
	 * The width must be between 100 and 300 pixels.<br/>
	 * @param app The media player application.<br/>
	 */
	private void setLibraryListWidth(final FxMedia app) {
		double libraryListWidth = app.getPlayer().getLibrary().getLongestSongName() * 5d;

		if(libraryListWidth > 300d) libraryListWidth = 300d;
		if(libraryListWidth < 100d) libraryListWidth = 100d;

        this.setPrefWidth(libraryListWidth);
	} // END setLibraryListWidth

	/**
	 * Adds a listener to the item selection property for the library list.<br/>
	 * @param app The media player application.<br/>
	 */
	private void initSelectionListener(final FxMedia app) {
		this.getSelectionModel().selectedItemProperty().addListener(
            new ChangeListener<MediaFile>() {
            	@Override
                public void changed(ObservableValue<? extends MediaFile> ov, MediaFile oldVal, MediaFile newVal) {
                	app.getPrevTrackButton().setDisable(null == newVal);
                	app.getPlayTrackButton().setDisable(null == newVal);
                	app.getNextTrackButton().setDisable(null == newVal);
	            } // END changed
            } // END ChangeListener
        );
	} // END initSelectionListener

	/**
	 * Adds an event handler to the list view node.<br/>
	 * @param app The media player application.<br/>
	 */
	private void initDoubleClickListener(final FxMedia app) {
		this.setOnMouseClicked(
			new EventHandler<MouseEvent>() {
				@Override
				public void handle(MouseEvent me) {
					if(1 < me.getClickCount()) {
						if(PlayButton.State.PUSH_TO_STOP == app.getPlayTrackButton().getState() || app.getPlayer().isPlaying()) {
							app.getPlayer().stop();
						} // END if

						app.getPlayTrackButton().playCurrentSelection(app);
					} // END if
				} // END handle
			} // END EventHandler
		);
	} // END initDoubleClickListener

	/**
	 * getUserAgentStylesheet.<br/>
	 * @return String The path to the style-sheet to use for styling this component.<br/>
	 */
	@Override
	protected String getUserAgentStylesheet() {
		System.out.println("LibraryList::getUserAgentStylesheet()");
		return LibraryList.class.getResource(Constants.CURRENT_SKIN).toExternalForm();
	} // END getUserAgentStylesheet

	/**
	 * Returns the previous track&apos;s index into this library list.<br/>
	 * @param shuffle If true, the previous track index return will be random, otherwise the previous track index will one less than the current track index.<br/>
	 * @return An index into this library list.<br/>
	 */
	public int getPreviousTrackIndex(boolean shuffle) {
		if(shuffle) {
			return new Random().nextInt(getItems().size()); // TODO
		} else {
			final int currFile = getSelectionModel().getSelectedIndex();
			final int numFiles = getItems().size();
			return (0 == currFile ? numFiles - 1 : currFile - 1);
		} // END if/else
	} // END getPreviousTrackIndex

	/**
	 * Returns the next track&apos;s index into this library list.<br/>
	 * @param shuffle If true, the next track index return will be random, otherwise the next track index will one greater than the current track index.<br/>
	 * @return An index into this library list.<br/>
	 */
	public int getNextTrackIndex(boolean shuffle) {
		if(shuffle) {
			return new Random().nextInt(getItems().size()); // TODO
		} else {
			final int currFile = getSelectionModel().getSelectedIndex();
			final int numFiles = getItems().size();
			return (currFile < numFiles - 1 ? currFile + 1 : 0);
		} // END if/else
	} // END getNextTrackIndex

	/**
	 * Selects an item within the library and updates the scroll position so that the selected item is visible.<br/>
	 * @param index The index to select.<br/>
	 */
	public void selectAndScrollTo(final int index) {
		try {
			getSelectionModel().select(index);
			// The scrollTo method must execute on a JavaFX thread.
			// This method may have been called from a user thread.
			Platform.runLater(new Runnable() {
	            @Override
	            public void run() {
	            	scrollTo(index);
	            } // END run
			});
		} catch(Exception exc) {
			System.out.printf("ERROR: Error setting index (%d of %d) and scrolling within the library: %s%n", index, getItems().size(), exc.getMessage());
			exc.printStackTrace();
		} // END try/catch
	} // END selectAndScrollTo
} // END class LibraryList
